/*=============================================================================
  D3DHDRRender.cpp : high dynamic range post-processing
  Copyright (c) 2001 Crytek Studios. All Rights Reserved.

    Revision history:
      * Created by Honich Andrey
			* 01.10.09: Started refactoring (Tiago Sousa)

=============================================================================*/

#include "StdAfx.h"
#include "DriverD3D.h"
#include "D3DPostProcess.h"
#include "I3DEngine.h"

//  render targets info - first gather list of hdr targets, sort by size and create after
struct SRenderTargetInfo
{
	DWORD               dwWidth;
	DWORD               dwHeight;
	ETEX_Format         Format;
	DWORD               dwFlags;
  CTexture            **lplpStorage;
	char                szName[64];
	DWORD               dwPitch;
	float               fPriority;
	int32               nCustomID;
	bool								bHiQuality;
};

struct RenderTargetSizeSort
{
	bool operator()( const SRenderTargetInfo &drtStart, const SRenderTargetInfo &drtEnd ) { return (drtStart.dwPitch*drtStart.fPriority) > (drtEnd.dwPitch*drtEnd.fPriority); }
};

class CHDRPostProcess
{

public:

	CHDRPostProcess()
	{
		nTexStateLinear = CTexture::GetTexState(STexState(FILTER_LINEAR, true));
		nTexStateLinearWrap = CTexture::GetTexState(STexState(FILTER_LINEAR, false));
		nTexStatePoint = CTexture::GetTexState(STexState(FILTER_POINT, true));
		nTexStatePointWrap = CTexture::GetTexState( STexState(FILTER_POINT, false));
		m_bHiQuality = false;
		m_shHDR = 0;
	}

	~CHDRPostProcess()
	{

	}

	void ScreenShot();

	void SetShaderParams();
	
	// Tone mapping steps
	void HalfResDownsampleHDRTarget();
	void QuarterResDownsampleHDRTarget();
	void MeasureLuminance();
	void EyeAdaptation();
	void BrightPass();
	void BloomAndFlares();
	void ProcessFlares();
	void ToneMapping(bool bUberPostEnabled); 
	void ToneMappingDebug();
	void DrawDebugViews();

	void Begin();
	void Render();
	void End();

	void AddRenderTarget( DWORD dwWidth, DWORD dwHeight, ETEX_Format Format, float fPriority, const char *szName, CTexture **pStorage, DWORD dwFlags=0, int32 nCustomID = -1, bool bHiQuality=0, bool bDynamicTex = 0);
	bool CreateRenderTargetList();
	void ClearRenderTargetList()
	{
		m_pRenderTargets.clear();
	}

	static CHDRPostProcess *GetInstance()
	{
		static CHDRPostProcess pInstance;
		return &pInstance;
	}

private:

	std::vector< SRenderTargetInfo > m_pRenderTargets;
	CShader *m_shHDR; 

	int32 nTexStateLinear;
	int32 nTexStateLinearWrap;
	int32 nTexStatePoint;
	int32 nTexStatePointWrap;

	bool m_bHiQuality;		
};

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

void CHDRPostProcess::AddRenderTarget( DWORD dwWidth, DWORD dwHeight, ETEX_Format Format, float fPriority, const char *szName, CTexture **pStorage,DWORD dwFlags, int32 nCustomID, bool bHiQuality, bool bDynamicTex)
{
	SRenderTargetInfo drt;
  drt.dwWidth          = dwWidth;
  drt.dwHeight         = dwHeight;
  drt.dwFlags          = FT_USAGE_RENDERTARGET | FT_DONT_STREAM | FT_DONT_RESIZE | dwFlags;
  drt.Format           = Format;
	drt.bHiQuality				= bHiQuality;
  drt.fPriority        = fPriority;
	drt.lplpStorage      = pStorage;
  drt.nCustomID        = nCustomID;
  strcpy_s(drt.szName, szName);
  drt.dwPitch          = dwWidth * CTexture::BytesPerPixel(Format);
  m_pRenderTargets.push_back( drt );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

bool CHDRPostProcess::CreateRenderTargetList()
{
  std::sort( m_pRenderTargets.begin(), m_pRenderTargets.end(), RenderTargetSizeSort() );

	for( uint32 t= 0; t <m_pRenderTargets.size(); ++t )
  {
    SRenderTargetInfo &drt = m_pRenderTargets[t];
    CTexture *tp = CTexture::CreateRenderTarget(drt.szName, drt.dwWidth, drt.dwHeight, eTT_2D, drt.dwFlags, drt.Format, drt.nCustomID, (int8)(drt.fPriority*100.0f)-5, drt.bHiQuality);

    if (tp)
    {
			*drt.lplpStorage = tp;
      ColorF c = Col_Black;
      tp->Fill(c);
    }
  }

  m_pRenderTargets.clear();

  return S_OK;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

void CTexture::GenerateHDRMaps()
{
  int i;
  char szName[256];

  CD3D9Renderer *r = gcpRendD3D;
	CHDRPostProcess *pHDRPostProcess = CHDRPostProcess::GetInstance();

	r->m_dwHDRCropWidth = r->GetWidth();
  r->m_dwHDRCropHeight = r->GetHeight();

  DestroyHDRMaps();
	
	pHDRPostProcess->ClearRenderTargetList();

	ETEX_Format nHDRFormat = eTF_A16B16G16R16F; // note: for main rendertarget R11G11B10 precision/range (even with rescaling) not enough for darks vs good blooming quality
	
	pHDRPostProcess->AddRenderTarget(r->GetWidth(), r->GetHeight(), nHDRFormat, 1.0f, "$HDRTarget", &s_ptexHDRTarget, ((CRenderer::CV_r_msaa ? FT_USAGE_MSAA : 0) ) );
#if defined( WIN32 ) || defined( gringo )
	pHDRPostProcess->AddRenderTarget(r->GetWidth(), r->GetHeight(), eTF_A8R8G8B8, 1.0f, "$HDRTargetPrevEncoded", &s_ptexHDRTargetPrev );
#endif
#if defined( PS3 )
  pHDRPostProcess->AddRenderTarget(r->GetWidth(), r->GetHeight(), eTF_A8R8G8B8, 1.0f, "$HDRTargetEncoded", &s_ptexHDRTargetEncoded, (CRenderer::CV_r_msaa ? FT_USAGE_MSAA : 0) | FT_USAGE_PREDICATED_TILING/*| FT_CUSTOM_FORMAT*/, TO_HDRTARGET_ENCODED);
#endif

	// Scaled versions of the HDR scene texture
  uint32 nWeight = (r->m_dwHDRCropWidth >>1); 
  uint32 nHeight = (r->m_dwHDRCropHeight >>1);
  pHDRPostProcess->AddRenderTarget(nWeight, nHeight, nHDRFormat ,0.9f, "$HDRTargetScaled0", &s_ptexHDRTargetScaled[0], FT_CUSTOM_FORMAT);
	
#if !defined(XENON) && !defined(PS3)
  // xenon/ps3 use custom rgbk encoding, can skip this target
	pHDRPostProcess->AddRenderTarget(nWeight, nHeight, nHDRFormat ,0.9f, "$HDRTargetScaledTmp0", &s_ptexHDRTargetScaledTmp[0], FT_CUSTOM_FORMAT);	
	pHDRPostProcess->AddRenderTarget(nWeight, nHeight, nHDRFormat ,0.9f, "$HDRTargetScaledTempRT0", &s_ptexHDRTargetScaledTempRT[0], FT_CUSTOM_FORMAT);

	#if defined (DIRECT3D10)
    const float fDofTargetScale = (CRenderer::CV_r_DofBokehQuality == 1)? 1.0f: 0.8f;
		pHDRPostProcess->AddRenderTarget((DWORD)(nWeight*fDofTargetScale), (DWORD)(nHeight*fDofTargetScale), nHDRFormat ,0.9f, "$HDRDofLayerNear", &s_ptexHDRDofLayers[0], FT_CUSTOM_FORMAT);	
		pHDRPostProcess->AddRenderTarget((DWORD)(nWeight*fDofTargetScale), (DWORD)(nHeight*fDofTargetScale), nHDRFormat ,0.9f, "$HDRDofLayerFar", &s_ptexHDRDofLayers[1], FT_CUSTOM_FORMAT);	
	#endif
	
#endif

  nWeight = (r->m_dwHDRCropWidth >>2);
  nHeight = (r->m_dwHDRCropHeight >>2);
  pHDRPostProcess->AddRenderTarget(nWeight, nHeight, nHDRFormat ,0.9f, "$HDRTargetScaled1", &s_ptexHDRTargetScaled[1], FT_CUSTOM_FORMAT);
	pHDRPostProcess->AddRenderTarget(nWeight, nHeight, nHDRFormat ,0.9f, "$HDRTargetScaledTmp1", &s_ptexHDRTargetScaledTmp[1], FT_CUSTOM_FORMAT);	
	
	pHDRPostProcess->AddRenderTarget(nWeight, nHeight, nHDRFormat ,0.9f, "$HDRTargetScaledTempRT1", &s_ptexHDRTargetScaledTempRT[1], FT_CUSTOM_FORMAT);

	pHDRPostProcess->AddRenderTarget(nWeight, nHeight, eTF_A8R8G8B8 ,0.9f, "$HDRFinalBloom", &s_ptexHDRFinalBloom, 0);		
		
	pHDRPostProcess->AddRenderTarget((r->m_dwHDRCropWidth>>3), (r->m_dwHDRCropHeight>>3),  nHDRFormat ,0.9f, "$HDRStreaksCache", &s_ptexHDRStreaksCache, FT_CUSTOM_FORMAT);		
	pHDRPostProcess->AddRenderTarget((r->m_dwHDRCropWidth>>3), (r->m_dwHDRCropHeight>>3), nHDRFormat ,0.9f, "$HDRTargetScaled2", &s_ptexHDRTargetScaled[2], FT_CUSTOM_FORMAT);
	pHDRPostProcess->AddRenderTarget((r->m_dwHDRCropWidth>>3), (r->m_dwHDRCropHeight>>3), nHDRFormat ,0.9f, "$HDRTargetScaledTmp2", &s_ptexHDRTargetScaledTmp[2], FT_CUSTOM_FORMAT);
	pHDRPostProcess->AddRenderTarget((r->m_dwHDRCropWidth>>3), (r->m_dwHDRCropHeight>>3), nHDRFormat ,0.9f, "$HDRTargetScaledTempRT2", &s_ptexHDRTargetScaledTempRT[2], FT_CUSTOM_FORMAT);

	pHDRPostProcess->AddRenderTarget((r->m_dwHDRCropWidth>>4), (r->m_dwHDRCropHeight>>4), nHDRFormat ,0.9f, "$HDRTargetScaled3", &s_ptexHDRTargetScaled[3], FT_CUSTOM_FORMAT);
	pHDRPostProcess->AddRenderTarget((r->m_dwHDRCropWidth>>4), (r->m_dwHDRCropHeight>>4), nHDRFormat ,0.9f, "$HDRTargetScaledTmp3", &s_ptexHDRTargetScaledTmp[3], FT_CUSTOM_FORMAT);
	pHDRPostProcess->AddRenderTarget((r->m_dwHDRCropWidth>>4), (r->m_dwHDRCropHeight>>4), nHDRFormat ,0.9f, "$HDRTargetScaledTempRT3", &s_ptexHDRTargetScaledTempRT[3], FT_CUSTOM_FORMAT);

  DWORD dwFlagsDyn = FT_DONT_STREAM | FT_DONT_RESIZE | FT_USAGE_READBACK;
	const int LocalRes	=	1;//CRenderer::CV_r_HDREyeAdaptationLocal==0?1:
												//CRenderer::CV_r_HDREyeAdaptationLocal==1?4:16;
	s_ptexCurLumTextureSys = CTexture::Create2DTexture("$HDRCurrLuminanceSys",LocalRes,LocalRes,0,dwFlagsDyn,0,eTF_G16R16F,eTF_G16R16F);

	for (i=0; i<8; i++)
  {
    sprintf(szName, "$HDRAdaptedLuminanceCur_%d", i);
    pHDRPostProcess->AddRenderTarget(LocalRes,LocalRes, /*r->m_HDR_FloatFormat_Scalar/ **/eTF_G16R16F, 0.1f, szName, &s_ptexHDRAdaptedLuminanceCur[i], 0, -1, true);
  }

	// Luminance rt
  for(i=0; i<NUM_HDR_TONEMAP_TEXTURES; i++)
  {
    int iSampleLen = 1 << (2*i);
    sprintf(szName, "$HDRToneMap_%d", i);
    pHDRPostProcess->AddRenderTarget(iSampleLen, iSampleLen, eTF_G16R16F/*r->m_HDR_FloatFormat_Scalar*/, 0.7f, szName, &s_ptexHDRToneMaps[i], 0, -1, true);
  }

  pHDRPostProcess->CreateRenderTargetList();

	r->m_vSceneLuminanceInfo = Vec4(1.0f, 1.0f, 1.0f, 1.0f);
	r->m_fAdaptedSceneScaleLBuffer = r->m_fAdaptedSceneScale = r->m_fStocopicSceneScale = 1.0f;

  // Create resources if necessary - todo: refactor all this shared render targets stuff, quite cumbersome atm...
  SPostEffectsUtils::Create(); 
























































}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

void CTexture::DestroyHDRMaps()
{
	int i;

	SAFE_RELEASE(s_ptexHDRTarget);
	SAFE_RELEASE(s_ptexHDRTargetPrev);
#if PS3
	SAFE_RELEASE(s_ptexHDRTargetEncoded);
#endif

	SAFE_RELEASE(s_ptexHDRTargetScaled[0]);
	SAFE_RELEASE(s_ptexHDRTargetScaled[1]);
	SAFE_RELEASE(s_ptexHDRTargetScaled[2]);
	SAFE_RELEASE(s_ptexHDRTargetScaled[3]);

#if !defined(XENON) && !defined(PS3)
	SAFE_RELEASE(s_ptexHDRTargetScaledTmp[0]);
	SAFE_RELEASE(s_ptexHDRTargetScaledTempRT[0]);

#if defined (DIRECT3D10)
	SAFE_RELEASE(s_ptexHDRDofLayers[0]);	
	SAFE_RELEASE(s_ptexHDRDofLayers[1]);	
#endif

#endif

	SAFE_RELEASE(s_ptexHDRTargetScaledTmp[1]);
	SAFE_RELEASE(s_ptexHDRTargetScaledTmp[2]);
	SAFE_RELEASE(s_ptexHDRTargetScaledTmp[3]);
	
	SAFE_RELEASE(s_ptexHDRTargetScaledTempRT[1]);
	SAFE_RELEASE(s_ptexHDRTargetScaledTempRT[2]);
	SAFE_RELEASE(s_ptexHDRTargetScaledTempRT[3]);

	SAFE_RELEASE(s_ptexHDRFinalBloom);
	SAFE_RELEASE(s_ptexHDRStreaksCache);
	
	SAFE_RELEASE(s_ptexCurLumTextureSys);

	for (i=0; i<8; i++)
	{
		SAFE_RELEASE(s_ptexHDRAdaptedLuminanceCur[i]);
	}

	for(i=0; i<NUM_HDR_TONEMAP_TEXTURES; i++)
	{
		SAFE_RELEASE(s_ptexHDRToneMaps[i]);
	}

	CTexture::s_ptexCurLumTexture = NULL;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

// deprecated
void DrawQuad3D(float s0, float t0, float s1, float t1)
{
  const float fZ=0.5f;
  const float fX0=-1.0f, fX1=1.0f;
  const float fY0=1.0f, fY1=-1.0f;

  gcpRendD3D->DrawQuad3D(Vec3(fX0,fY1,fZ), Vec3(fX1,fY1,fZ), Vec3(fX1,fY0,fZ), Vec3(fX0,fY0,fZ), Col_White, s0, t0, s1, t1);
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

// deprecated
void DrawFullScreenQuadTR(float xpos, float ypos, float w, float h)
{
  uint32 nOffs;
  SVF_P3F_C4B_T2F *vQuad = (SVF_P3F_C4B_T2F *)gcpRendD3D->m_DynVB[POOL_P3F_COL4UB_TEX2F].LockVB(4, nOffs);

  DWORD col = ~0;

  // Now that we have write access to the buffer, we can copy our vertices
  // into it

  const float s0 = 0;
  const float s1 = 1;
  const float t0 = 1;
  const float t1 = 0;

  // Define the quad
  vQuad[0].xyz = Vec3(xpos, ypos, 1.0f);
  vQuad[0].color.dcolor = col;
  vQuad[0].st = Vec2(s0, 1.0f-t0);

  vQuad[1].xyz = Vec3(xpos+w, ypos, 1.0f);
  vQuad[1].color.dcolor = col;
  vQuad[1].st = Vec2(s1, 1.0f-t0);

  vQuad[3].xyz = Vec3(xpos+w, ypos+h, 1.0f);
  vQuad[3].color.dcolor = col;
  vQuad[3].st = Vec2(s1, 1.0f-t1);

  vQuad[2].xyz = Vec3(xpos, ypos+h, 1.0f);
  vQuad[2].color.dcolor = col;
  vQuad[2].st = Vec2(s0, 1.0f-t1);

  // We are finished with accessing the vertex buffer
  gcpRendD3D->m_DynVB[POOL_P3F_COL4UB_TEX2F].UnlockVB();

  gcpRendD3D->FX_Commit();

  // Bind our vertex as the first data stream of our device
  gcpRendD3D->m_DynVB[POOL_P3F_COL4UB_TEX2F].Bind();
  if (!FAILED(gcpRendD3D->FX_SetVertexDeclaration(0, eVF_P3F_C4B_T2F)))
  {
		// Render the two triangles from the data stream
		gcpRendD3D->FX_DrawPrimitive(eptTriangleStrip, nOffs, 4);
  }
}

#define NV_CACHE_OPTS_ENABLED TRUE

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

// deprecated
void DrawFullScreenQuad(float fLeftU, float fTopV, float fRightU, float fBottomV, bool bClampToScreenRes)
{
//#ifndef XENON
	
  D3DSURFACE_DESC dtdsdRT;
  memset(&dtdsdRT, 0, sizeof(dtdsdRT));
  CD3D9Renderer *rd = gcpRendD3D;

  rd->FX_Commit();

  // Acquire render target width and height
#if defined (DIRECT3D9)
  PDIRECT3DSURFACE9 pSurfRT = NULL;
  rd->m_pd3dDevice->GetRenderTarget(0, &pSurfRT);
	if( !pSurfRT ) // prevent crash when no render target is bound
		return;

  pSurfRT->GetDesc(&dtdsdRT);
  pSurfRT->Release();
#elif defined (DIRECT3D10)
  dtdsdRT.Width = rd->m_NewViewport.nWidth;
  dtdsdRT.Height = rd->m_NewViewport.nHeight;
#endif

  bool bNV = NV_CACHE_OPTS_ENABLED;
#if defined (XENON) || defined (DIRECT3D10)
  bNV = false;
#endif
  // Ensure that we're directly mapping texels to pixels by offset by 0.5
  // For more info see the doc page titled "Directly Mapping Texels to Pixels"
  int nWidth = dtdsdRT.Width;
  int nHeight = dtdsdRT.Height;
	if(bClampToScreenRes)
	{
		nWidth = min(nWidth, rd->GetWidth());
		nHeight = min(nHeight, rd->GetHeight());
	}

  float fWidth5 = (float)nWidth;
  float fHeight5 = (float)nHeight;
  fWidth5 = (bNV) ?  (2.f*fWidth5) - 0.5f : fWidth5 - 0.5f;
  fHeight5 = (bNV) ? (2.f*fHeight5)- 0.5f : fHeight5 - 0.5f;

  // Draw the quad
  uint32 nOffs;
  SVF_TP3F_C4B_T2F *Verts = (SVF_TP3F_C4B_T2F *)rd->m_DynVB[POOL_TRP3F_COL4UB_TEX2F].LockVB(bNV?3:4, nOffs);
	assert(Verts);
#if defined(DIRECT3D9) && (defined(WIN32) || defined(WIN64))
	if (Verts)
#endif
	{
#if defined (DIRECT3D10) || defined (XENON)
		fTopV = 1 - fTopV;
		fBottomV = 1 - fBottomV;
#endif







		Verts[0].pos = Vec4(-0.5f, -0.5f, 0.0f, 1.0f);
		Verts[0].color.dcolor = ~0;
		Verts[0].st = Vec2(fLeftU, fTopV);
		if (bNV)
		{
			float tWidth = fRightU - fLeftU;
			float tHeight = fBottomV - fTopV;
			Verts[1].pos = Vec4(fWidth5, -0.5f, 0.0f, 1.f);
			Verts[1].color.dcolor = ~0;
			Verts[1].st = Vec2(fLeftU + (tWidth*2.f), fTopV);

			Verts[2].pos = Vec4(-0.5f, fHeight5, 0.0f, 1.f);
			Verts[2].color.dcolor = ~0;
			Verts[2].st = Vec2(fLeftU, fTopV + (tHeight*2.f));
		}
		else
		{
			Verts[1].pos = Vec4(fWidth5, -0.5f, 0.0f, 1.0f);
			Verts[1].color.dcolor = ~0;
			Verts[1].st = Vec2(fRightU, fTopV);

			Verts[2].pos = Vec4(-0.5f, fHeight5, 0.0f, 1.0f);
			Verts[2].color.dcolor = ~0;
			Verts[2].st = Vec2(fLeftU, fBottomV);

			Verts[3].pos = Vec4(fWidth5, fHeight5, 0.0f, 1.0f);
			Verts[3].color.dcolor = ~0;
			Verts[3].st = Vec2(fRightU, fBottomV);
		}




		rd->m_DynVB[POOL_TRP3F_COL4UB_TEX2F].UnlockVB();

		rd->FX_SetState(GS_NODEPTHTEST);
		if (!FAILED(rd->FX_SetVertexDeclaration(0, eVF_TP3F_C4B_T2F)))
		{
			rd->m_DynVB[POOL_TRP3F_COL4UB_TEX2F].Bind();
			rd->FX_DrawPrimitive(eptTriangleStrip, nOffs, (bNV)?3:4);
		}
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

// deprecated
void DrawFullScreenQuad(CoordRect c, bool bClampToScreenRes)
{
	DrawFullScreenQuad( c.fLeftU, c.fTopV, c.fRightU, c.fBottomV, bClampToScreenRes );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

void GetSampleOffsets_DownScale4x4( uint32 nWidth, uint32 nHeight, Vec4 avSampleOffsets[])
{
  float tU = 1.0f / (float)nWidth;
  float tV = 1.0f / (float)nHeight;

  // Sample from the 16 surrounding points. Since the center point will be in
  // the exact center of 16 texels, a 0.5f offset is needed to specify a texel
  // center.
  int index=0;
  for(int y=0; y<4; y++)
  {
    for(int x=0; x<4; x++)
    {
      avSampleOffsets[index].x = (x - 1.5f) * tU;
      avSampleOffsets[index].y = (y - 1.5f) * tV;
      avSampleOffsets[index].z = 0;
      avSampleOffsets[index].w = 1;

      index++;
    }
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

void GetSampleOffsets_DownScale4x4Bilinear( uint32 nWidth, uint32 nHeight, Vec4 avSampleOffsets[])
{
  float tU = 1.0f / (float)nWidth;
  float tV = 1.0f / (float)nHeight;

  // Sample from the 16 surrounding points.  Since bilinear filtering is being used, specific the coordinate
  // exactly halfway between the current texel center (k-1.5) and the neighboring texel center (k-0.5)

  int index=0;
  for(int y=0; y<4; y+=2)
  {
    for(int x=0; x<4; x+=2, index++)
    {
      avSampleOffsets[index].x = (x - 1.f) * tU;
      avSampleOffsets[index].y = (y - 1.f) * tV;
      avSampleOffsets[index].z = 0;
      avSampleOffsets[index].w = 1;
    }
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

void GetSampleOffsets_DownScale2x2( uint32 nWidth, uint32 nHeight, Vec4 avSampleOffsets[] )
{
  float tU = 1.0f / (float)nWidth;
  float tV = 1.0f / (float)nHeight;

  // Sample from the 4 surrounding points. Since the center point will be in
  // the exact center of 4 texels, a 0.5f offset is needed to specify a texel
  // center.
  int index=0;
  for( int y=0; y < 2; y++ )
  {
    for( int x=0; x < 2; x++ )
    {
      avSampleOffsets[index].x = (x - 0.5f) * tU;
      avSampleOffsets[index].y = (y - 0.5f) * tV;
      avSampleOffsets[index].z = 0;
      avSampleOffsets[index].w = 1;

      index++;
    }
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

void CHDRPostProcess::SetShaderParams()
{
	CD3D9Renderer *r = gcpRendD3D;

	static CCryNameR Param1Name("HDRParams0");
	static CCryNameR Param2Name("HDRParams1");
	static CCryNameR Param3Name("HDRParams2");
	static CCryNameR Param4Name("HDRParams3");
	static CCryNameR Param5Name("HDRParams4");
	static CCryNameR Param6Name("HDRParams5");
	static CCryNameR Param7Name("HDRParams6");
	static CCryNameR Param8Name("HDRParams7");
	static CCryNameR Param9Name("HDRParams8");
  static CCryNameR Param10Name("HDRParams9");

	Vec4 v;
	Vec4 vHDRSetupParams[7];
	gEnv->p3DEngine->GetHDRSetupParams( vHDRSetupParams );

	bool bNightVisionToneMap = gRenDev->IsCustomRenderModeEnabled( eRMF_NIGHTVISION );

	CPostEffectsMgr *pPostMgr = PostEffectMgr();
	CEffectParam *m_pUserHDRBrightLevel = pPostMgr->GetByName("Global_User_HDRBrightLevel");
	CEffectParam *m_pUserHDRBrightThreshold = pPostMgr->GetByName("Global_User_HDRBrightThreshold");

	// When nightvision mode enabled - override bloom settings for customized look
	float fEyeAdaptationFactor = CRenderer::CV_r_HDREyeAdaptationFactor;
	float fHDRBrightLevel = CRenderer::CV_r_HDRBrightLevel * max(1.0f, vHDRSetupParams[0].y) + m_pUserHDRBrightLevel->GetParam(); // clamp to 1 to prevent silly usage and loss of precision
	if( bNightVisionToneMap ) 
	{
		//fEyeAdaptationFactor = 0.5f;
		fHDRBrightLevel = CRenderer::CV_r_NightVisionBrightLevel;
		// Custom settings for flares/streaks
		//vHDRSetupParams[2] *= 1.5f;
		vHDRSetupParams[3] = Vec4(Vec3(0.05f, 0.05f, 0.05f), CRenderer::CV_r_NightVisionFinalMul);
		vHDRSetupParams[4] = Vec4(Vec3(0.5f, 0.5f, 0.5f), CRenderer::CV_r_NightVisionFinalMul);
	}

	// To maximize precision on bloom we keep original re-scale
	v[0] = CRenderer::CV_r_HDREyeAdaptationFactor;
	v[1] = CRenderer::CV_r_HDRBrightOffset;

  // ???
	// apply gamma correction to bright offset
	if (r->IsLinearSpaceShadingEnabled())
		v[1] *= v[1];

	v[2] = CRenderer::CV_r_HDRBrightThreshold + m_pUserHDRBrightThreshold->GetParam();	
	v[3] = fHDRBrightLevel; 

	m_shHDR->FXSetPSFloat(Param1Name, &v, 1);

	v[0] = CRenderer::CV_r_HDREyeAdaptationBase;
	v[1] = CRenderer::CV_r_HDRLevel; 
	v[2] = CRenderer::CV_r_HDROffset; 

	// Output eye adaptation into register
	v[3] = CRenderer::CV_r_HDREyeAdaptationBase * (1.0f - fEyeAdaptationFactor) + fEyeAdaptationFactor * r->m_vSceneLuminanceInfo.x;

	// Output computed adapted luminance, instead of computing in pixel shader ( half fAdaptedLumDest = HDRParams1.y / (1e-6 + 1.0h + HDRParams1.z * fAdaptedLum) )
	if( CRenderer:: CV_r_HDRRangeAdapt ) 	
		v[1] = v[1] / (1e-6f + 1.0f + v[2] * v[3] ); 

	m_shHDR->FXSetPSFloat(Param2Name, &v, 1);

	v[0] = r->m_vSceneLuminanceInfo.x;
	v[1] = 1.0f / r->m_fAdaptedSceneScale; 
	v[2] = vHDRSetupParams[0].x;
	v[3] = 1.0f;
	m_shHDR->FXSetPSFloat(Param3Name, &v, 1);

	vHDRSetupParams[1].x *= vHDRSetupParams[1].x;
	vHDRSetupParams[1].y *= vHDRSetupParams[1].y;
	vHDRSetupParams[1].z *= vHDRSetupParams[1].z;
	vHDRSetupParams[1].w = div_min(1.f, vHDRSetupParams[1].w * CRenderer::CV_r_HDRBlueShift, 1e6f);
	float fHdrBloomMul = CRenderer::CV_r_HDRBloomMul;

	vHDRSetupParams[2].x *= fHdrBloomMul;
	vHDRSetupParams[2].y *= fHdrBloomMul;
	vHDRSetupParams[2].z *= fHdrBloomMul;
	vHDRSetupParams[2].w = max(vHDRSetupParams[2].w, CRenderer::CV_r_HDRGrainAmount);

	m_shHDR->FXSetPSFloat(Param5Name, &vHDRSetupParams[1], 1);
	m_shHDR->FXSetPSFloat(Param6Name, &vHDRSetupParams[2], 1);
	m_shHDR->FXSetPSFloat(Param7Name, &vHDRSetupParams[3], 1);
	m_shHDR->FXSetPSFloat(Param8Name, &vHDRSetupParams[4], 1);		

  // deprecated c2 post tone mapping scurve - to be removed when film curve used by default
	Vec4 vHDRSCSetupParams = Vec4( CRenderer::CV_r_HDRSCurveMin, CRenderer::CV_r_HDRSCurveMax, CRenderer::CV_r_HDRSaturation, CRenderer::CV_r_HDRBrightness);
  vHDRSCSetupParams = vHDRSetupParams[5];   //m_fHDRShoulderScale, m_fHDRMidtonesScale, m_fHDRToeScale, m_fHDRWhitePoint

	m_shHDR->FXSetPSFloat(Param9Name, &vHDRSCSetupParams, 1);
  
  vHDRSCSetupParams = vHDRSetupParams[6];   //m_vColorBalance.x, m_vColorBalance.y, m_vColorBalance.z, m_fHDRSaturation
  m_shHDR->FXSetPSFloat(Param10Name, &vHDRSCSetupParams, 1);

	bool bHalfResMbDof = (CRenderer::CV_r_MotionBlur || CRenderer::CV_r_dof) /*&& (m_bHiQuality == false)*/ && CRenderer::CV_r_PostProcess;
	Vec4 vDofParams = Vec4(0.0f, 0.0f, 0.0f, 0.0f);
	if( bHalfResMbDof )
	{
		CDepthOfField *pDofRenderTech = (CDepthOfField *)PostEffectMgr()->GetEffect(ePFX_eDepthOfField);
		SDepthOfFieldParams pDofParams = pDofRenderTech->GetParams();	
		pDofParams.vFocus.w *= 2.0f;

		// prebake parameters in cpu side
		Vec4 vFocus = pDofParams.vFocus;

		if( pDofParams.bGameMode )
		{		
			pDofParams.vFocus.x = 1.0f / (vFocus.z + 1e-6f);
			pDofParams.vFocus.y = - vFocus.y / (vFocus.z + 1e-6f);
		}
		else
		{
			pDofParams.vFocus.x = 1.0f / (vFocus.y + 1e-6f);
			pDofParams.vFocus.y = - vFocus.z / (vFocus.y + 1e-6f);
		}

		if( vFocus.w < 0.1f )
			pDofParams.vFocus = Vec4(0,0,0,0);

		vDofParams = pDofParams.vFocus;
	}

	static CCryNameR ParamDofName("HDRDofParams");	
	m_shHDR->FXSetPSFloat(ParamDofName, &vDofParams, 1);		
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

void CHDRPostProcess::HalfResDownsampleHDRTarget()
{ 
	PROFILE_LABEL_PUSH( "HALFRES_DOWNSAMPLE_HDRTARGET" );

  CTexture *pSrcRT = CTexture::s_ptexHDRTarget;
  CTexture *pDstRT = CTexture::s_ptexHDRTargetScaledTmp[0];
  bool bEncodeRGBK = false;
  





  PostProcessUtils().StretchRect( pSrcRT, pDstRT, false, false, bEncodeRGBK);	

	PROFILE_LABEL_POP( "HALFRES_DOWNSAMPLE_HDRTARGET" );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

void CHDRPostProcess::QuarterResDownsampleHDRTarget()
{  
	PROFILE_LABEL_PUSH( "QUARTER_RES_DOWNSAMPLE_HDRTARGET" );

  CTexture *pSrcRT = ( !CRenderer::CV_r_MotionBlur && !CRenderer::CV_r_dof)? CTexture::s_ptexHDRTargetScaledTmp[0] : CTexture::s_ptexHDRTargetScaled[0];
  CTexture *pDstRT = CTexture::s_ptexHDRTargetScaled[1];
  bool bDecodeRGBK = false;






  PostProcessUtils().StretchRect( pSrcRT, pDstRT, false, bDecodeRGBK);

	PROFILE_LABEL_POP( "QUARTER_RES_DOWNSAMPLE_HDRTARGET" );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

void CHDRPostProcess::MeasureLuminance()
{
  PROFILE_LABEL_PUSH( "MEASURE_LUMINANCE" );	
  
  int x, y, index;
  Vec4 avSampleOffsets[16];
  CD3D9Renderer *rd = gcpRendD3D;

	uint64 nFlagsShader_RT = gRenDev->m_RP.m_FlagsShader_RT;
	gRenDev->m_RP.m_FlagsShader_RT &= ~(g_HWSR_MaskBit[HWSR_SAMPLE0]|g_HWSR_MaskBit[HWSR_SAMPLE1]|g_HWSR_MaskBit[HWSR_SAMPLE2]|g_HWSR_MaskBit[HWSR_SAMPLE5]);





  int32 dwCurTexture = NUM_HDR_TONEMAP_TEXTURES-1;
  static CCryNameR Param1Name("SampleOffsets");

  // Initialize the sample offsets for the initial luminance pass.
  float tU, tV;
  tU = 1.0f / (3.0f * CTexture::s_ptexHDRToneMaps[dwCurTexture]->GetWidth());
  tV = 1.0f / (3.0f * CTexture::s_ptexHDRToneMaps[dwCurTexture]->GetHeight());

  index=0;
  for(x=-1; x<=1; x++)
  {
    for(y=-1; y<=1; y++)
    {
      avSampleOffsets[index].x = x * tU;
      avSampleOffsets[index].y = y * tV;
      avSampleOffsets[index].z = 0;
      avSampleOffsets[index].w = 1;

      index++;
    }
  }

	ColorF clearColor(0, 0, 0, 0);
	uint32 nPasses;

	rd->FX_PushRenderTarget(0, CTexture::s_ptexHDRToneMaps[dwCurTexture], NULL);
	rd->RT_SetViewport(0, 0, CTexture::s_ptexHDRToneMaps[dwCurTexture]->GetWidth(), CTexture::s_ptexHDRToneMaps[dwCurTexture]->GetHeight());        
  
	static CCryNameTSCRC TechName("HDRSampleLumInitial");
	m_shHDR->FXSetTechnique(TechName);  
	m_shHDR->FXBegin(&nPasses, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
	m_shHDR->FXBeginPass(0);

  CTexture::s_ptexHDRTargetScaled[1]->Apply(0, nTexStateLinear /*nTexStatePoint*/);

	float s1 = 1.0f / (float) CTexture::s_ptexHDRTargetScaled[1]->GetWidth();
	float t1 = 1.0f / (float) CTexture::s_ptexHDRTargetScaled[1]->GetHeight();       

	// Use rotated grid
	Vec4 vSampleLumOffsets0 = Vec4(s1*0.95f, t1*0.25f, -s1*0.25f, t1*0.96f); 
	Vec4 vSampleLumOffsets1 = Vec4(-s1*0.96f, -t1*0.25f, s1*0.25f, -t1*0.96f);  

	static CCryNameR pSampleLumOffsetsName0("SampleLumOffsets0");
	static CCryNameR pSampleLumOffsetsName1("SampleLumOffsets1");

	m_shHDR->FXSetPSFloat(pSampleLumOffsetsName0, &vSampleLumOffsets0, 1);        
	m_shHDR->FXSetPSFloat(pSampleLumOffsetsName1, &vSampleLumOffsets1, 1); 

	SetShaderParams();

  // Draw a fullscreen quad to sample the RT
  DrawFullScreenQuad(0.0f, 0.0f, 1.0f, 1.0f);

  m_shHDR->FXEndPass();

	rd->FX_PopRenderTarget(0);

  dwCurTexture--;

  // Initialize the sample offsets for the iterative luminance passes
  while(dwCurTexture >= 0)
  {
    rd->FX_PushRenderTarget(0, CTexture::s_ptexHDRToneMaps[dwCurTexture], NULL);
		rd->RT_SetViewport(0, 0, CTexture::s_ptexHDRToneMaps[dwCurTexture]->GetWidth(), CTexture::s_ptexHDRToneMaps[dwCurTexture]->GetHeight());        

		if( !dwCurTexture )
			gRenDev->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE0];

    static CCryNameTSCRC TechNameLI("HDRSampleLumIterative");
    m_shHDR->FXSetTechnique(TechNameLI);
    m_shHDR->FXBegin(&nPasses, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
    m_shHDR->FXBeginPass(0);
    if (rd->m_bDeviceSupportsFP16Filter)
    {
      GetSampleOffsets_DownScale4x4Bilinear(CTexture::s_ptexHDRToneMaps[dwCurTexture+1]->GetWidth(), CTexture::s_ptexHDRToneMaps[dwCurTexture+1]->GetHeight(), avSampleOffsets);
      m_shHDR->FXSetPSFloat(Param1Name, avSampleOffsets, 4);
      CTexture::s_ptexHDRToneMaps[dwCurTexture+1]->Apply(0, nTexStateLinear);
    }
    else
    {
      GetSampleOffsets_DownScale4x4(CTexture::s_ptexHDRToneMaps[dwCurTexture+1]->GetWidth(), CTexture::s_ptexHDRToneMaps[dwCurTexture+1]->GetHeight(), avSampleOffsets);

      m_shHDR->FXSetPSFloat(Param1Name, avSampleOffsets, 16);
      CTexture::s_ptexHDRToneMaps[dwCurTexture+1]->Apply(0, nTexStatePoint);
    }

    // Draw a fullscreen quad to sample the RT
    DrawFullScreenQuad(0.0f, 0.0f, 1.0f, 1.0f);

    m_shHDR->FXEndPass();

		rd->FX_PopRenderTarget(0);

    dwCurTexture--;
  }

  PROFILE_LABEL_POP( "MEASURE_LUMINANCE" );





	gRenDev->m_RP.m_FlagsShader_RT = nFlagsShader_RT;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

void CHDRPostProcess::EyeAdaptation()
{
  PROFILE_LABEL_PUSH( "EYEADAPTATION" );
  
  CD3D9Renderer *rd = gcpRendD3D;

  // Swap current & last luminance
  int nCurLum = CTexture::s_nCurLumTextureIndex++;
	nCurLum &= CD3D9Renderer::ELumMask;
	CTexture *pTexPrev = CTexture::s_ptexHDRAdaptedLuminanceCur[(nCurLum-1)&CD3D9Renderer::ELumMask];
  CTexture *pTexCur = CTexture::s_ptexHDRAdaptedLuminanceCur[nCurLum];
  CTexture::s_ptexCurLumTexture = pTexCur;
  assert(pTexCur);

  uint32 nPasses;
  static CCryNameTSCRC TechName("HDRCalculateAdaptedLum");
  m_shHDR->FXSetTechnique(TechName);
  m_shHDR->FXBegin(&nPasses, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);

  rd->FX_PushRenderTarget(0, pTexCur, NULL);
	rd->RT_SetViewport(0, 0, pTexCur->GetWidth(), pTexCur->GetHeight());        

  m_shHDR->FXBeginPass(0);

  Vec4 v;
  v[0] = iTimer->GetFrameTime();
	v[1] = 1 - powf( 0.98f, CRenderer::CV_r_HDREyeAdaptationSpeed * 33.0f * v[0]);
  v[2] = 1 - powf( 0.98f, CRenderer::CV_r_HDRRangeAdaptationSpeed * 33.0f * v[0]);
  v[3] = 0;
  static CCryNameR Param1Name("ElapsedTime");
  m_shHDR->FXSetPSFloat(Param1Name, &v, 1);
  pTexPrev->Apply(0, nTexStatePoint);
	const int LocalRes	=	max(min(CRenderer::CV_r_HDREyeAdaptationLocal,2),0);
  CTexture::s_ptexHDRToneMaps[LocalRes]->Apply(1, nTexStatePoint);

  // Draw a fullscreen quad to sample the RT
  DrawFullScreenQuad(0.0f, 0.0f, 1.0f, 1.0f);

  m_shHDR->FXEndPass();

	rd->FX_PopRenderTarget(0);







  PROFILE_LABEL_POP( "EYEADAPTATION" );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

void CD3D9Renderer::FX_HDRRangeAdaptUpdate()
{
	CD3D9Renderer *rd = gcpRendD3D;

	if( CRenderer:: CV_r_HDRRangeAdapt ) 
	{
		// Swap current & last luminance
		int nCurLum = CTexture::s_nCurLumTextureIndex;
		int nCurLumAdaptIdx			= (nCurLum-2) & ELumMask;

		//D3DSurface *pSrcDevSurf = pTex->GetSurface(0, 0);
		//D3DSurface *pDstDevSurfSys = CTexture::s_ptexCurLumTextureSys->GetSurface(0, 0);

//		D3DXFLOAT16 *hSurfSys = 0;
		float pLumInfo[2];
		pLumInfo[0] = pLumInfo[1] = 0;




#if defined(DIRECT3D9) || defined(CAFE)

		STexLock rect;  
		CTexture *pTexPrev = CTexture::s_ptexHDRAdaptedLuminanceCur[nCurLumAdaptIdx];

		STALL_PROFILER("update scene luminance")

		CTexture *pTex = pTexPrev;//CTexture::s_ptexCurLumTexture;
		CDeviceTexture *pSrcDevTex = pTex->GetDevTexture();//CTexture::s_ptexCurLumTexture->GetDevTexture();
		CDeviceTexture *pDstDevTex = CTexture::s_ptexCurLumTextureSys->GetDevTexture();		  
		assert(pSrcDevTex);
		assert(pDstDevTex);
		
#if !defined (XENON)
		//hr = rd->m_pd3dDevice->GetRenderTargetData(pSrcDevSurf, pDstDevSurfSys);
#endif
		if (SUCCEEDED(pSrcDevTex->LockRect(0, rect, LF_READ)) ) 
		{
			//hSurfSys = ((D3DXFLOAT16*)rect.pData);
			//D3DXFloat16To32Array (pLumInfo, hSurfSys, 2);

			CryHalf *pRawPtr = (CryHalf*) rect.pData;
			pLumInfo[0] = CryConvertHalfToFloat( pRawPtr[0] );
			pLumInfo[1] = CryConvertHalfToFloat( pRawPtr[1] );						

			pSrcDevTex->UnlockRect(0);

			//SAFE_RELEASE(pSrcDevSurf);
			//SAFE_RELEASE(pDstDevSurfSys);
		}

#endif
		
		// note: RG16F - channels are swapped 
		rd->m_vSceneLuminanceInfo.x = pLumInfo[1];	// avg
		rd->m_vSceneLuminanceInfo.y = pLumInfo[0];//0;//pLumInfo[2];	// min - instead of min, maybe we can simplify and output maybe 4x smaller luminance
		//rd->m_vSceneLuminanceInfo.z = ;	// max

		// For night/very dark scenes boost maximum range
		const float fStocopicThreshold = 0.01f;
		rd->m_fStocopicSceneScale += (( (rd->m_vSceneLuminanceInfo.x < fStocopicThreshold)? 2.0f : 1.0f) - rd->m_fStocopicSceneScale ) * gEnv->pTimer->GetFrameTime(); 

		// Tweakable scene range scale. 
		// Optimaly we could rescale to take advantage of full texture format range into account, but we need to maintain acceptable range for blooming (else we get very poor bloom quality)
		rd->m_fAdaptedSceneScale = CRenderer::CV_r_HDRRangeAdaptMax / (1e-6f + rd->m_vSceneLuminanceInfo.y);
		rd->m_fAdaptedSceneScale = max(1.0f, min(rd->m_fAdaptedSceneScale, CRenderer::CV_r_HDRRangeAdaptMaxRange * rd->m_fStocopicSceneScale) );

		// todo: we need to try out different strategies for light buffers (different scales for day/night scenes? we hit top clamping too often)
		
		// Light buffers range scale
		rd->m_fAdaptedSceneScaleLBuffer = CRenderer::CV_r_HDRRangeAdaptLBufferMax / (1e-6f + rd->m_vSceneLuminanceInfo.y);
		rd->m_fAdaptedSceneScaleLBuffer = max(1.0f, min(rd->m_fAdaptedSceneScaleLBuffer, CRenderer::CV_r_HDRRangeAdaptLBufferMaxRange * rd->m_fStocopicSceneScale) );

		//rd->m_fAdaptedSceneScaleLBuffer = max(1.0f, min(rd->m_vSceneLuminanceInfo.y, CRenderer::CV_r_HDRRangeAdaptLBufferMaxRange * rd->m_fStocopicSceneScale) );

	}
	else
	{
		rd->m_vSceneLuminanceInfo = Vec4(1.0f, 1.0f, 1.0f, 1.0f);;
		rd->m_fAdaptedSceneScale = 1.0f;
		rd->m_fAdaptedSceneScaleLBuffer = 1.0f;
		rd->m_fStocopicSceneScale = 1.0f;
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

void CHDRPostProcess::BrightPass()
{
	// Note, for consoles we merge brightpass with initial blur step, easy 0.1ms save

  PROFILE_LABEL_PUSH( "BRIGHTPASS" );

	gcpRendD3D->Set2DMode(true, 1, 1);   
  
  CD3D9Renderer *rd = gcpRendD3D;
  uint32 nPasses;

  uint64 nFlagsShader_RT = gRenDev->m_RP.m_FlagsShader_RT;
  gRenDev->m_RP.m_FlagsShader_RT &= ~(g_HWSR_MaskBit[HWSR_SAMPLE0]|g_HWSR_MaskBit[HWSR_SAMPLE1]|g_HWSR_MaskBit[HWSR_SAMPLE2]|g_HWSR_MaskBit[HWSR_SAMPLE5]);
	if(gRenDev->IsLinearSpaceShadingEnabled())
		gRenDev->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE0]; 

	static CCryNameTSCRC TechName("HDRBrightPassFilter");

	rd->FX_PushRenderTarget(0, CTexture::s_ptexHDRTargetScaledTmp[1], NULL);
	rd->RT_SetViewport(0, 0, CTexture::s_ptexHDRTargetScaledTmp[1]->GetWidth(), CTexture::s_ptexHDRTargetScaledTmp[1]->GetHeight());        

  m_shHDR->FXSetTechnique(TechName);
  m_shHDR->FXBegin(&nPasses, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);

  m_shHDR->FXBeginPass(0);
  SetShaderParams();

	int32 nCurrTexState = nTexStatePoint;




	CTexture::s_ptexHDRTargetScaled[1]->Apply(0, nCurrTexState);

  if (CTexture::s_ptexCurLumTexture && !CRenderer::CV_r_HDRRangeAdapt)
    CTexture::s_ptexCurLumTexture->Apply(1, nTexStateLinear/*nTexStatePoint*/);

	SPostEffectsUtils::DrawFullScreenQuad( CTexture::s_ptexHDRTargetScaledTmp[1]->GetWidth(), CTexture::s_ptexHDRTargetScaledTmp[1]->GetHeight() );

  m_shHDR->FXEndPass();

	rd->FX_PopRenderTarget(0);  






















	gcpRendD3D->Set2DMode(false, 1, 1);
	gRenDev->m_RP.m_FlagsShader_RT = nFlagsShader_RT;

  PROFILE_LABEL_POP( "BRIGHTPASS" );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

void CHDRPostProcess::BloomAndFlares()
{
	// Prepare input texture for bloom/flares
	BrightPass();

	PROFILE_LABEL_PUSH( "BLOOM_AND_FLARES" );

	uint32 nPasses = 0;
	gcpRendD3D->Set2DMode(true, 1, 1);      

	CD3D9Renderer *rd = gcpRendD3D; 

	// Bloom generation/intermediate render-targets
	CTexture *pBloomGen[3];         
	// Final bloom RT
	CTexture *pBloom = 0; 




	pBloomGen[0] = CTexture::s_ptexHDRTargetScaledTmp[1];  // 4x


	pBloomGen[1] = CTexture::s_ptexHDRTargetScaled[2];  // 8x
	pBloomGen[2] = CTexture::s_ptexHDRTargetScaled[3];  // 16x

	// Bloom/Glow generation: 
	//  - using 3 textures, each with half resolution of previous, Gaussian blurred and result summed up at end

	/////////////////////////////////////////////////////////////////////////////////////////////////
	// bright pass and blur pBloomGen0

#if !defined(XENON) && !defined(PS3) && !defined(CAFE)
	// blur was already done in previous merged brightpass - for pc specs use higher quality
	PostProcessUtils().TexBlurGaussian( pBloomGen[0], 1, 1.0f, 3.0f, false, 0, false, CTexture::s_ptexHDRTargetScaledTempRT[1]);      
#endif

	//if( CRenderer::CV_r_glow ==2 )	
	//PostProcessUtils().TexBlurIterative( pBloomGen[0], 1, 0, CTexture::s_ptexHDRTargetScaledTempRT[1]);

	PostProcessUtils().StretchRect( pBloomGen[0], pBloomGen[1] );      
	PostProcessUtils().TexBlurGaussian( pBloomGen[1], 1, 1.0f, 3.0f, false, 0, false, CTexture::s_ptexHDRTargetScaledTempRT[2]);   

	PostProcessUtils().StretchRect( pBloomGen[1], pBloomGen[2] );                 
	PostProcessUtils().TexBlurGaussian( pBloomGen[2], 1, 1.0f, 3.0f, false, 0, false, CTexture::s_ptexHDRTargetScaledTempRT[3]);

	ProcessFlares();    

	gcpRendD3D->Set2DMode(false, 1, 1);      

	PROFILE_LABEL_POP( "BLOOM_AND_FLARES" );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

// Deprecated
void CHDRPostProcess::ProcessFlares()
{
	// Process flares
	PROFILE_LABEL_PUSH( "HDR_FLARES" );

	// Bloom generation/intermediate render-targets
	CTexture *pFlaresGen[3];        




	pFlaresGen[0] = CTexture::s_ptexHDRTargetScaledTmp[1];


	pFlaresGen[1] = CTexture::s_ptexHDRTargetScaled[2];
	pFlaresGen[2] = CTexture::s_ptexHDRTargetScaled[3];

	CTexture *pCurrBloomFrame = CTexture::s_ptexHDRFinalBloom;

	gcpRendD3D->FX_PushRenderTarget(0, pCurrBloomFrame, NULL); 
	gcpRendD3D->RT_SetViewport(0, 0, pCurrBloomFrame->GetWidth(), pCurrBloomFrame->GetHeight());

	static CCryNameTSCRC pTechNameFlares("HDRFlares"); 
	GetUtils().ShBeginPass(CShaderMan::m_shHDRPostProcess, pTechNameFlares, FEF_DONTSETTEXTURES|FEF_DONTSETSTATES);   

	gcpRendD3D->FX_SetState(GS_NODEPTHTEST);     

	GetUtils().SetTexture(pFlaresGen[0], 0, FILTER_POINT);   // don't waste tex performance, if destination is same res, use point filtering...    
	GetUtils().SetTexture(pFlaresGen[1], 1, FILTER_LINEAR);    
	GetUtils().SetTexture(pFlaresGen[2], 2, FILTER_LINEAR);    

	CTexture::s_ptexGrainFilterMap->Apply(5, nTexStatePointWrap); 
	SetShaderParams();

	SPostEffectsUtils::DrawFullScreenQuad( CTexture::s_ptexHDRFinalBloom->GetWidth(), CTexture::s_ptexHDRFinalBloom->GetHeight() );

	GetUtils().ShEndPass();   

	gcpRendD3D->FX_PopRenderTarget(0);

	PROFILE_LABEL_POP( "HDR_FLARES" );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

void CHDRPostProcess::ToneMapping(bool bUberPostEnabled)
{
	CD3D9Renderer *rd = gcpRendD3D;
	SRenderPipeline& RESTRICT_REFERENCE rRP = rd->m_RP;

	if (!gcpRendD3D->m_pColorGradingControllerD3D)
		return;

	CSunShafts *pSunShaftsTech = (CSunShafts *)PostEffectMgr()->GetEffect(ePFX_SunShafts);
	CPostAA *pPostAATech = (CPostAA*)PostEffectMgr()->GetEffect(ePFX_PostAA);

	CTexture *pSunShaftsRT = 0;
	if( pSunShaftsTech && bUberPostEnabled && CRenderer::CV_r_sunshafts && CRenderer::CV_r_PostProcess)
	{
		rd->Set2DMode(true, 1, 1);

		/////////////////////////////////////////////
		// Create shafts mask texture

		uint32 nWidth = CTexture::s_ptexBackBufferScaled[1]->GetWidth();
		uint32 nHeight = CTexture::s_ptexBackBufferScaled[1]->GetHeight();
		pSunShaftsRT = CTexture::s_ptexBackBufferScaled[1];
#if !defined(XENON) && !defined(PS3) && !defined(CAFE)
		if( rRP.m_eQuality >= eRQ_High)
		{
			pSunShaftsRT = CTexture::s_ptexGlow[0];
			nWidth = CTexture::s_ptexGlow[0]->GetWidth();
			nHeight = CTexture::s_ptexGlow[0]->GetHeight();
		}
#endif	

		pSunShaftsTech->SunShaftsGen(pSunShaftsRT, rRP.m_eQuality >= eRQ_High ? CTexture::s_ptexBackBufferScaledTemp[0] : CTexture::s_ptexBackBufferScaledTemp[1]);
		rd->Set2DMode(false, 1, 1); 
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// Update color grading

	bool bColorGrading = false;

	SColorGradingMergeParams pMergeParams;
	if( bUberPostEnabled && CRenderer::CV_r_colorgrading && CRenderer::CV_r_colorgrading_charts )
	{
		CColorGrading *pColorGrad = 0;
		if( !PostEffectMgr()->GetEffects().empty() )
			pColorGrad =  static_cast<CColorGrading*>( PostEffectMgr()->GetEffect(ePFX_ColorGrading) );

		if(pColorGrad->UpdateParams( pMergeParams ))
			bColorGrading = true;
	}

	CColorGradingControllerD3D* pCtrl = gcpRendD3D->m_pColorGradingControllerD3D; 
	CTexture *pTexColorChar = pCtrl? pCtrl->GetColorChart() : 0;

	rd->RT_SetViewport(0, 0, CTexture::s_ptexHDRTarget->GetWidth(), CTexture::s_ptexHDRTarget->GetHeight());         

	PROFILE_LABEL_PUSH( "TONEMAPPING" );

	////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// Enable corresponding shader variation
	rRP.m_FlagsShader_RT &= ~(g_HWSR_MaskBit[HWSR_SAMPLE0]|g_HWSR_MaskBit[HWSR_SAMPLE1]|g_HWSR_MaskBit[HWSR_SAMPLE2]|g_HWSR_MaskBit[HWSR_SAMPLE3]|g_HWSR_MaskBit[HWSR_SAMPLE5]|g_HWSR_MaskBit[HWSR_SAMPLE4]);

	if(bUberPostEnabled)
		rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE0];
	if(CRenderer::CV_r_HDRRangeAdapt)
		rRP.m_FlagsShader_RT |=	g_HWSR_MaskBit[HWSR_SAMPLE4];

	// Enable night vision tone mapper
	if( gRenDev->IsCustomRenderModeEnabled( eRMF_NIGHTVISION ) )
		rRP.m_FlagsShader_RT |=	g_HWSR_MaskBit[HWSR_SAMPLE5];

	if( bColorGrading && pTexColorChar)
		rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE1];

	if( CRenderer::CV_r_HDRDebug == 5)
		rRP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_DEBUG0];

	rd->FX_SetMSAAFlagsRT();
	
	////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  // Final bloom RT

	CTexture *pBloom = CTexture::s_ptexBlack;
	if( CRenderer::CV_r_glow && CRenderer::CV_r_PostProcess)
		pBloom = CTexture::s_ptexHDRFinalBloom;

  uint32 nPasses;
  static CCryNameTSCRC TechFinalName("HDRFinalPass");
  m_shHDR->FXSetTechnique(TechFinalName);
  m_shHDR->FXBegin(&nPasses, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
  m_shHDR->FXBeginPass(0);

  // Set all shader params
	SetShaderParams();

	// For Post SSAA
	Matrix44 mPrevViewProj = pPostAATech->GetPrevViewProj();
	static CCryNameR pParamPrevViewProj("mViewProjPrev");
	m_shHDR->FXSetPSFloat(pParamPrevViewProj, (Vec4 *)mPrevViewProj.GetData(), 4);    

	Vec4 vHDRParams3 = Vec4(0.0f, 1, 0, 0);
	static CCryNameR pszHDRParam3("HDRParams3");
	m_shHDR->FXSetPSFloat(pszHDRParam3, &vHDRParams3, 1);

  static uint32 dwNoiseOffsetX=0;
  static uint32 dwNoiseOffsetY=0;
  dwNoiseOffsetX = (dwNoiseOffsetX+27)&0x3f;
  dwNoiseOffsetY = (dwNoiseOffsetY+19)&0x3f;

  Vec4 pFrameRand(((float)dwNoiseOffsetX)/64.0f, ((float)dwNoiseOffsetX)/64.0f, ((float)(cry_rand()%1024))/1024.0f, ((float)(cry_rand()%1024))/1024.0f );
  static CCryNameR Param4Name("FrameRand");
  m_shHDR->FXSetVSFloat(Param4Name, &pFrameRand, 1);

  static CCryNameR pSunShaftsParamSName("SunShafts_SunCol");
  Vec4 pShaftsSunCol(0,0,0,0);
  if( pSunShaftsRT ) 
  {
    Vec4 pSunShaftsParams[2];
    pSunShaftsTech->GetSunShaftsParams(pSunShaftsParams);
    Vec3 pSunColor = gEnv->p3DEngine->GetSunColor();
    pSunColor.Normalize();
    pSunColor.SetLerp( Vec3(pSunShaftsParams[0].x, pSunShaftsParams[0].y, pSunShaftsParams[0].z), pSunColor, pSunShaftsParams[1].w ); 

    pShaftsSunCol = Vec4( pSunColor * pSunShaftsParams[1].z, 1);
  }

  m_shHDR->FXSetPSFloat(pSunShaftsParamSName, &pShaftsSunCol, 1);

  // Force commit before setting samplers - workaround for per frame samplers hardcoded/overriding sampler slots
  rd->FX_Commit();

  CTexture::s_ptexHDRTarget->Apply(0, nTexStatePoint, -1, -1, rRP.m_MSAAData.Type? 4 : -1);  // bind as msaa target (if valid)
	if (CTexture::s_ptexCurLumTexture && !CRenderer::CV_r_HDRRangeAdapt)
    CTexture::s_ptexCurLumTexture->Apply(1, nTexStateLinear/*nTexStatePoint*/);

	pBloom->Apply(2, nTexStateLinear);

	// Lower specs use half res motion blur/depth of field
	bool bHalfResMbDof = (CRenderer::CV_r_MotionBlur || CRenderer::CV_r_dof) /*&& (m_bHiQuality == false)*/ && CRenderer::CV_r_PostProcess;
	// Fast path on consoles - RGBK encoding
	CTexture *pMbDofSrc = bHalfResMbDof? CTexture::s_ptexBackBufferScaled[0]:CTexture::s_ptexBlackAlpha;
	CTexture *pMbDofMask = bHalfResMbDof? CTexture::s_ptexHalfResCompositionMask:CTexture::s_ptexBlackAlpha;
#if !defined(XENON) && !defined(PS3)
	// Use FP target on pc, mask in alpha
	if( bHalfResMbDof )
		pMbDofSrc = CTexture::s_ptexHDRTargetScaled[0];		
#endif

	pMbDofSrc->Apply(3, nTexStateLinear);
	pMbDofMask->Apply(4, nTexStateLinear);	

	CTexture::s_ptexZTarget->Apply(5, nTexStatePoint);

	CTexture::s_ptexGrainFilterMap->Apply(6, nTexStatePointWrap); 
	
	if( CRenderer::CV_r_PostProcess && CRenderer::CV_r_HDRVignetting)
		CTexture::s_ptexVignettingMap->Apply(7, nTexStateLinear);
	else
		CTexture::s_ptexWhite->Apply(7, nTexStateLinear);

	if( pTexColorChar )
		pTexColorChar->Apply( 8, nTexStateLinear);

  if( pSunShaftsRT ) 
    pSunShaftsRT->Apply(9, nTexStateLinear);

	CTexture::s_ptexBackBuffer->Apply(12, nTexStatePoint);


	SD3DPostEffectsUtils::DrawFullScreenQuadWPOS(CTexture::s_ptexBackBuffer->GetWidth(), CTexture::s_ptexBackBuffer->GetHeight());

  PROFILE_LABEL_POP( "TONEMAPPING" );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

void CHDRPostProcess::ToneMappingDebug()
{	  
  CD3D9Renderer *rd = gcpRendD3D;
  Vec4 avSampleOffsets[4];

	if( CRenderer::CV_r_HDRDebug == 1)
		gRenDev->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_DEBUG0];
	else
		gRenDev->m_RP.m_FlagsShader_RT &= ~g_HWSR_MaskBit[HWSR_DEBUG0];
	
	uint32 nPasses;
	static CCryNameTSCRC techName("HDRFinalDebugPass");
  m_shHDR->FXSetTechnique(techName);
  m_shHDR->FXBegin(&nPasses, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
  m_shHDR->FXBeginPass(0);

  GetSampleOffsets_DownScale2x2(CTexture::s_ptexHDRTarget->GetWidth(), CTexture::s_ptexHDRTarget->GetHeight(), avSampleOffsets);
 	static CCryNameR SampleOffsetsName("SampleOffsets");
  m_shHDR->FXSetPSFloat(SampleOffsetsName, avSampleOffsets, 4);

  CTexture::s_ptexHDRTarget->Apply(0, nTexStatePoint);
  DrawFullScreenQuad( 0.0f, 0.0f, 1.0f, 1.0f );

	gRenDev->m_RP.m_FlagsShader_RT &= ~g_HWSR_MaskBit[HWSR_DEBUG0];
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

void CHDRPostProcess::DrawDebugViews()
{
  if (CRenderer::CV_r_HDRDebug != 3 && CRenderer::CV_r_HDRDebug != 4)
		return;
	
  if (!gRenDev->IsHDRModeEnabled())
		return;

  CD3D9Renderer *rd = gcpRendD3D;
	uint32 nPasses = 0;

  rd->FX_SetState(GS_NODEPTHTEST);
  int iTmpX, iTmpY, iTempWidth, iTempHeight;
  rd->GetViewport(&iTmpX, &iTmpY, &iTempWidth, &iTempHeight);   
	
  rd->EF_SetColorOp(eCO_MODULATE, eCO_MODULATE, DEF_TEXARG0, DEF_TEXARG0);
  rd->Set2DMode(true, 1, 1);

	gRenDev->m_cEF.mfRefreshSystemShader("Debug", CShaderMan::m_ShaderDebug);
  CShader *pSH = CShaderMan::m_ShaderDebug;

  CTexture *pSceneTargetHalfRes = ( !CRenderer::CV_r_MotionBlur && !CRenderer::CV_r_dof)? CTexture::s_ptexHDRTargetScaledTmp[0] : CTexture::s_ptexHDRTargetScaled[0];



  CTexture::s_ptexHDRTarget->SetResolved(false);
  CTexture::s_ptexHDRTarget->Resolve();

  //pSceneTargetHalfRes = CTexture::s_ptexBackBufferScaled[0];
  // 1
	uint32 nPosX = 100;
  rd->RT_SetViewport(nPosX, 500, 100, 100);   
  rd->DrawImage(0, 0, 1, 1, CTexture::s_ptexHDRTarget->GetID(), 0, 1, 1, 0, 1,1,1,1);

  // 2
  rd->RT_SetViewport(nPosX += 110, 500, 100, 100);   
  rd->DrawImage(0, 0, 1, 1, pSceneTargetHalfRes->GetID(), 0, 1, 1, 0, 1,1,1,1);

  // 3
  if( CRenderer::CV_r_glow )
  {    
    // Bloom generation/intermediate render-targets
    CTexture *pBloomGen[3];         
    // Final bloom RT
    CTexture *pBloom = 0; 
    



		pBloomGen[0] = CTexture::s_ptexHDRTargetScaledTmp[1];  // 4x

    pBloomGen[1] = CTexture::s_ptexHDRTargetScaled[2];  // 4x         ''
    pBloomGen[2] = CTexture::s_ptexHDRTargetScaled[3];  // 8x         ''
 
    rd->RT_SetViewport(nPosX += 110, 500, 100, 100);   
    rd->DrawImage(0, 0, 1, 1, pBloomGen[0]->GetID(), 0, 1, 1, 0, 1,1,1,1);

    rd->RT_SetViewport(nPosX += 110, 500, 100, 100);
    rd->DrawImage(0, 0, 1, 1, pBloomGen[1]->GetID(), 0, 1, 1, 0, 1,1,1,1);

    rd->RT_SetViewport(nPosX += 110, 500, 100, 100);
    rd->DrawImage(0, 0, 1, 1, pBloomGen[2]->GetID(), 0, 1, 1, 0, 1,1,1,1);
		
		CTexture *pCurrBloomFrame = CTexture::s_ptexHDRFinalBloom;
		rd->RT_SetViewport(nPosX += 110, 500, 100, 100);  
		rd->DrawImage(0, 0, 1, 1, pCurrBloomFrame->GetID(), 0, 1, 1, 0, 1,1,1,1);
		
  }

	nPosX = 10;

	pSH->FXSetTechnique("Debug_ShowR");
	pSH->FXBegin(&nPasses, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
	pSH->FXBeginPass(0);

	CTexture::s_ptexHDRToneMaps[3]->Apply(0, nTexStatePoint);
	rd->RT_SetViewport(nPosX, 610, 100, 100);   
	DrawFullScreenQuadTR(0.0f, 0.0f, 1.0f, 1.0f);  

	if (CTexture::s_ptexHDRToneMaps[2])
	{
		CTexture::s_ptexHDRToneMaps[2]->Apply(0, nTexStatePoint);
		rd->RT_SetViewport(nPosX += 110, 610, 100, 100);   
		DrawFullScreenQuadTR(0.0f, 0.0f, 1.0f, 1.0f);
	}

	if (CTexture::s_ptexHDRToneMaps[1])
	{
		CTexture::s_ptexHDRToneMaps[1]->Apply(0, nTexStatePoint);
		rd->RT_SetViewport(nPosX += 110, 610, 100, 100);   
		DrawFullScreenQuadTR(0.0f, 0.0f, 1.0f, 1.0f);
	}

	if (CTexture::s_ptexHDRToneMaps[0])
	{
		CTexture::s_ptexHDRToneMaps[0]->Apply(0, nTexStatePoint);
		rd->RT_SetViewport(nPosX += 110, 610, 100, 100);   
		DrawFullScreenQuadTR(0.0f, 0.0f, 1.0f, 1.0f);
	}

	if (CTexture::s_ptexCurLumTexture)
	{
		CTexture::s_ptexCurLumTexture->Apply(0, nTexStatePoint);
		rd->RT_SetViewport(nPosX += 110, 610, 100, 100);   
		DrawFullScreenQuadTR(0.0f, 0.0f, 1.0f, 1.0f);
	}
	
	pSH->FXEndPass();
	pSH->FXEnd();

  rd->Set2DMode(false, 1, 1);
  rd->RT_SetViewport(iTmpX, iTmpY, iTempWidth, iTempHeight);   

	{
		char str[256];

		SDrawTextInfo ti;
	
		sprintf(str,"HDR rendering debug");
		rd->Draw2dText(5,310,str,ti);

		if( CRenderer::CV_r_HDRRangeAdapt ) 
		{
			sprintf(str,"Range adaption enabled");
			rd->Draw2dText(10,325,str,ti);
		}
	}

	if( CRenderer::CV_r_HDRDebug == 4 )
	{
		char str[256];
		SDrawTextInfo ti;
		sprintf(str,"Avg Luminance: %.5f \nMin Luminance: %.5f \nAdapted scene scale: %.5f\nAdapted light buffer scale: %.5f",  
			rd->m_vSceneLuminanceInfo.x, rd->m_vSceneLuminanceInfo.y, rd->m_fAdaptedSceneScale, rd->m_fAdaptedSceneScaleLBuffer);
		rd->Draw2dText(5,5,str,ti);
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

void CHDRPostProcess::ScreenShot()
{
	if(CRenderer::CV_r_GetScreenShot==1)
	{
#if defined (DIRECT3D9)
		char path[ICryPak::g_nMaxPath];
		path[sizeof(path) - 1] = 0;
		gEnv->pCryPak->AdjustFileName("%USER%/ScreenShots", path, ICryPak::FLAGS_PATH_REAL|ICryPak::FLAGS_FOR_WRITING);

		if (!gEnv->pCryPak->MakeDir(path))
		{
			iLog->Log("Cannot save screen shot! Failed to create directory \"%s\".", path);
		}
		else
		{
			char pszFileName[1024];

			int i=0;
			for(i=0 ; i<10000; i++)
			{
				snprintf(pszFileName, sizeof(pszFileName), "%s/ScreenShot%04d.hdr", path, i);
				pszFileName[sizeof(pszFileName)-1] = '\0';

				FILE *fp= fxopen(pszFileName, "rb");
				if(!fp)
					break;

				fclose(fp);
			}

			if(i==10000)
			{
				iLog->LogError("Cannot save ScreenShot: Too many HDR files");
				return;
			}


			D3DSurface *pHDRSurf = CTexture::s_ptexHDRTarget->GetSurface(-1, 0);
			D3DXSaveSurfaceToFile(pszFileName, D3DXIFF_HDR, pHDRSurf, 0, 0);
			SAFE_RELEASE(pHDRSurf);
		}
#else
		iLog->LogError("HDR screen shots are not yet supported on DX11!");		// TODO: D3DXSaveSurfaceToFile()
#endif
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

void CHDRPostProcess::Begin()
{
  gcpRendD3D->GetModelViewMatrix( PostProcessUtils().m_pView.GetData() );
  gcpRendD3D->GetProjectionMatrix( PostProcessUtils().m_pProj.GetData() );
	if( CRenderer::CV_r_PostAAMode <= 2 )
		SPostEffectsUtils::m_iFrameCounter=(SPostEffectsUtils::m_iFrameCounter+1)%1000;  

  // Store some commonly used per-frame data

  PostProcessUtils().m_pViewProj = PostProcessUtils().m_pView * PostProcessUtils().m_pProj;
  PostProcessUtils().m_pViewProj.Transpose();

	m_shHDR = CShaderMan::m_shHDRPostProcess;

	if (CTexture::s_ptexHDRTarget->GetWidth() != gcpRendD3D->GetWidth() || CTexture::s_ptexHDRTarget->GetHeight() != gcpRendD3D->GetHeight())
		CTexture::GenerateHDRMaps();
	
	gcpRendD3D->FX_ResetPipe();
	PostProcessUtils().SetFillModeSolid(true);





}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

void CHDRPostProcess::End()
{
	gcpRendD3D->m_RP.m_TI[gcpRendD3D->m_RP.m_nProcessThreadID].m_PersFlags &= ~RBPF_HDR;
	gcpRendD3D->m_RP.m_PersFlags2 &= ~(RBPF2_HDR_FP16 | RBPF2_LIGHTSHAFTS);

	gcpRendD3D->FX_ResetPipe();

	PostProcessUtils().SetFillModeSolid(false);

	CTexture::s_ptexHDRTarget->hintRelease();
	CTexture::s_ptexHDRTargetScaled[0]->hintRelease();
	CTexture::s_ptexHDRTargetScaled[1]->hintRelease();
#if defined( PS3 )
	CTexture::s_ptexHDRTargetEncoded->hintRelease();
#endif

	// (re-set back-buffer): due to lazy RT updates/setting there's strong possibility we run into problems on x360 when we try to resolve from edram with no RT set
	gcpRendD3D->FX_SetActiveRenderTargets();





}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

void CHDRPostProcess::Render()
{	
	if(!gRenDev->IsHDRModeEnabled())
		return;

	GPU_TIMER_START( "HDR" );
	PROFILE_LABEL_PUSH( "HDR_POSTPROCESS" );

	Begin();

	assert(gcpRendD3D->m_RTStack[0][gcpRendD3D->m_nRTStackLevel[0]].m_pTex == CTexture::s_ptexHDRTarget);
	
  gcpRendD3D->FX_SetActiveRenderTargets(); // Called explicitly to work around RT stack problems on 360
	gcpRendD3D->FX_PopRenderTarget(0);
  gcpRendD3D->EF_ClearBuffers(0, NULL);	

	// Skip hdr/post processing when rendering different camera views
	if( (gcpRendD3D->m_RP.m_TI[gcpRendD3D->m_RP.m_nProcessThreadID].m_PersFlags&RBPF_MIRRORCULL) )
	{		
		End();
		PROFILE_LABEL_POP( "HDR_POSTPROCESS" );
		GPU_TIMER_STOP( "HDR" );
		return;
	}

	// Render to intermediate target, to avoid redundant imagecopy/stretchrect for post msaa
	if( gRenDev->CV_r_PostProcess && CRenderer::CV_r_PostAA && PostProcessUtils().GetMsaaRT( true ) && PostProcessUtils().GetMsaaRT( false ) && !gRenDev->m_RP.m_MSAAData.Type)
	{ 
		CTexture *pDstRT = PostProcessUtils().GetMsaaRT( true );
		assert( pDstRT );
#if !defined(XENON)
		gcpRendD3D->FX_PushRenderTarget(0, pDstRT, &gcpRendD3D->m_DepthBufferOrig);
		gcpRendD3D->RT_SetViewport(0, 0, pDstRT->GetWidth(), pDstRT->GetHeight());         
#endif
	}

#if !defined(_RELEASE) || defined(WIN32) || defined(WIN64) || defined(ENABLE_LW_PROFILERS)
	ScreenShot();
#endif

	gcpRendD3D->m_RP.m_FlagsShader_RT = 0;

	if (gRenDev->IsLinearSpaceShadingEnabled())
		gcpRendD3D->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE0];
	if(CRenderer::CV_r_HDRRangeAdapt)
		gRenDev->m_RP.m_FlagsShader_RT |=	g_HWSR_MaskBit[HWSR_SAMPLE4];

	gcpRendD3D->FX_ApplyShaderQuality(eST_PostProcess);  
	m_bHiQuality = CPostEffectsMgr::CheckPostProcessQuality( eRQ_Low, eSQ_VeryHigh );

#ifdef SUPPORTS_MSAA	
  CTexture::s_ptexHDRTarget->SetResolved( false );
  CTexture::s_ptexHDRTarget->Resolve();
  gcpRendD3D->FX_SetMSAAFlagsRT();
#endif

  if( CRenderer::CV_r_SSReflections )
    PostProcessUtils().StretchRect(CTexture::s_ptexHDRTarget, CTexture::s_ptexHDRTargetPrev, false, false, true);

	if( CRenderer::CV_r_PostProcess )
	{
		HalfResDownsampleHDRTarget();

		// hdr post processes (dof/motion blur) - these reuse previous downsampled hdr target
		gcpRendD3D->FX_PostProcessSceneHDR();

		QuarterResDownsampleHDRTarget();
	}

		gcpRendD3D->FX_ApplyShaderQuality(eST_PostProcess);

	if( (SPostEffectsUtils::m_iFrameCounter % max(1, (int)CRenderer::CV_r_HDREyeAdaptionCache)) == 0 )
	{  
		// Update eye adaptation
		MeasureLuminance();
		EyeAdaptation();
	}

	if( CRenderer::CV_r_glow && CRenderer::CV_r_PostProcess )
		BloomAndFlares();

	// Render final scene to the back buffer
	if (CRenderer::CV_r_HDRDebug != 1 && CRenderer::CV_r_HDRDebug != 2)
		ToneMapping(true); 
	else
		ToneMappingDebug();

	if (CRenderer::CV_r_HDRDebug > 0)
		DrawDebugViews();

#ifdef SUPPORTS_MSAA
  if ( gRenDev->m_RP.m_MSAAData.Type && CRenderer::CV_r_msaa_debug >= 2)
  {
    static CCryNameTSCRC pMsaaDebugTech("MsaaDebug");
    PostProcessUtils().ShBeginPass(CShaderMan::m_shPostAA, pMsaaDebugTech, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
    uint32 nRS = GS_NODEPTHTEST;
    if( CRenderer::CV_r_msaa_debug == 2)
      nRS |= GS_BLSRC_ONE|GS_BLDST_ONE;
    gRenDev->FX_SetState(nRS);
    PostProcessUtils().SetTexture(CTexture::s_ptexBackBuffer, 0, FILTER_POINT);
    PostProcessUtils().DrawFullScreenQuad(CTexture::s_ptexBackBuffer->GetWidth(), CTexture::s_ptexBackBuffer->GetHeight(), 0, true);
    PostProcessUtils().ShEndPass();	
  }
#endif

	End();

	PROFILE_LABEL_POP( "HDR_POSTPROCESS" );
	GPU_TIMER_STOP( "HDR" );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

void CD3D9Renderer::FX_HDRPostProcessing()
{  	
	PROFILE_FRAME(Draw_HDR_PostProcessing);


  if (gcpRendD3D->m_bDeviceLost)
    return;

	if (!CTexture::IsTextureExist(CTexture::s_ptexHDRTarget))
		return;

	CHDRPostProcess *pHDRPostProcess = CHDRPostProcess::GetInstance();
	pHDRPostProcess->Render();
}
